iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
AI Engineering

從行程到應援:30 天做出追星實用工具箱系列 第 15 篇

Day 15:從逐字稿到流暢語意/串接 LLM(GPT-4o-mini / Gemini)進行翻譯

  • 分享至 

  • xImage
  •  

今天我們將實作一個翻譯服務,串接 OpenAI (GPT-4o-mini) 或 Google Gemini API,利用訂定好的規範讓語音辨識結果修飾為自然、流暢且符合語境的翻譯文句!

一、今日目標

  1. 設計翻譯專用 System Prompt:修飾口語贅字、自動補全標點,並輸出符合語境的譯文。
  2. 實作 LLM 翻譯服務:支援 GPT-4o-mini 或 Gemini API 串接。
  3. 整合架構:把翻譯服務安放至 live_translate/data/services/ 中。

二、今日任務

Step 1: 設計「語音翻譯專用」System Prompt

AI 翻譯好壞的關鍵在於 Prompt,一般的翻譯指令容易把口誤也照單全收,必須透過 Prompt 規範:

System Prompt 範例:
「你是一位精通多國語言的即時同聲傳譯專家,請依照以下規範將翻譯變得流暢。
原則:

  1. 自動過濾口頭禪、贅字(如:呃、那個、語氣詞)。
  2. 修正語音辨識可能產生的同音錯別字。
  3. 保持語意通順流暢,符合目標語言的道地表達方式。
  4. 僅輸出翻譯後的文本,不要包含任何解釋、引號或額外文字。」

Step 2: 實作(translation_service.dart)

在 lib/features/live_translate/data/services/ 下建立 translation_service.dart:

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_dotenv/flutter_dotenv.dart';

class TranslationService {
  final String _openAiUrl = 'https://api.openai.com/v1/chat/completions';

  /// 將原始逐字稿丟給 GPT-4o-mini 進行語意修飾與翻譯
  Future<String?> translateText({
    required String rawText,
    required String targetLanguage, // 例如: '繁體中文', '日本語', 'English'
  }) async {
    if (rawText.trim().isEmpty) return '';

    final apiKey = dotenv.env['OPENAI_API_KEY'];
    if (apiKey == null || apiKey.isEmpty) {
      print('錯誤:未設定 OPENAI_API_KEY');
      return null;
    }

    try {
      final response = await http.post(
        Uri.parse(_openAiUrl),
        headers: {
          'Content-Type': 'application/json; charset=utf-8',
          'Authorization': 'Bearer $apiKey',
        },
        body: jsonEncode({
          'model': 'gpt-4o-mini', // 性價比高、回應速度極快的首選模型
          'temperature': 0.3,     // 低隨機性,確保翻譯精準度
          'messages': [
            {
              'role': 'system',
              'content': '''你是一位同聲傳譯專家。請將輸入的語音逐字稿翻譯為 $targetLanguage。
要求:
1. 自動修剪語音贅詞(如:呃、這個、那個)。
2. 自動修正同音錯字並補充標點符號。
3. 語意順暢自然,符合標的語言習慣。
4. 僅回傳翻譯結果,嚴禁輸出任何說明。'''
            },
            {
              'role': 'user',
              'content': rawText,
            }
          ],
        }),
      );

      if (response.statusCode == 200) {
        final data = jsonDecode(utf8.decode(response.bodyBytes));
        final translatedText = data['choices'][0]['message']['content'];
        return translatedText?.toString().trim();
      } else {
        print('翻譯 API 錯誤 [${response.statusCode}]: ${response.body}');
        return null;
      }
    } catch (e) {
      print('翻譯請求異常: $error');
      return null;
    }
  }
}

Step 3: 在 UI 中調用翻譯服務 (multi_lang_page.dart)

更新你的 multi_lang_page.dart,在 Whisper 取得原始逐字稿(STT)後,立刻丟給 TranslationService:

// 在 State 中宣告翻譯服務
final TranslationService _translationService = TranslationService();

String _rawTranscript = '';     // 原始 STT 逐字稿
String _translatedText = '';   // LLM 修飾後的最終翻譯

// 處理語音流程
void _processAudioAndTranslate(File audioFile) async {
  setState(() => _isLoading = true);

  // 1. 先用 Whisper 取得原始逐字稿 (STT)
  final rawResult = await _whisperService.transcribe(
    audioFile: audioFile,
    config: _selectedLang,
  );

  if (rawResult != null && rawResult.isNotEmpty) {
    _rawTranscript = rawResult;

    // 2. 將原始逐字稿送往 GPT-4o-mini 翻譯修飾
    final translated = await _translationService.translateText(
      rawText: rawResult,
      targetLanguage: '繁體中文', // 設定你想翻譯成的目標語言
    );

    setState(() {
      _translatedText = translated ?? '翻譯失敗';
      _isLoading = false;
    });
  } else {
    setState(() {
      _rawTranscript = '未辨識到聲音';
      _isLoading = false;
    });
  }
}

檢查清單

可以做個小測試,對著麥克風講一段口誤的日文:

  1. 語音輸入:あー、えっと、今日の天気は…天気はとても良いですね。
  2. Whisper 原始逐字稿:あー、えっと、今日の天気は…天気はとても良いですね。
  3. LLM 翻譯後成果:今天的天氣非常好。 (自動去除了「あー、えっと」等語氣詞,並重組為順暢句子!)

上一篇
Day 14:開發踩坑週記/語音切片時遇到的音訊變形難題
下一篇
Day 16:解決 AI 聽不懂飯圈梗!設計「偶像暱稱與專有名詞」Prompt 字典
系列文
從行程到應援:30 天做出追星實用工具箱 共 16 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言